package com.lzp.controller.center;

import com.lzp.controller.BaseController;
import com.lzp.pojo.Users;
import com.lzp.pojo.bo.center.CenterUserBO;
import com.lzp.pojo.vo.UsersVO;
import com.lzp.resource.FileUpload;
import com.lzp.service.center.CenterUserService;
import com.lzp.utils.CookieUtils;
import com.lzp.utils.DateUtil;
import com.lzp.utils.JsonUtils;
import com.lzp.utils.ServerResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author dtyy
 * @date 2020/10/12
 */
@Api(value = "用户信息接口", tags = "用户信息接口")
@RestController
@RequestMapping("userInfo")
public class CenterUserController extends BaseController {

    @Autowired
    private CenterUserService centerUserService;

    @Autowired
    private FileUpload fileUpload;

    @ApiOperation(value = "修改用户头像", notes = "修改用户头像", httpMethod = "POST")
    @PostMapping("/uploadFace")
    public ServerResponse uploadFace(
            @ApiParam(name = "userId", value = "用户id", required = true)
            @RequestParam String userId,
            @ApiParam(name = "file", value = "用户头像", required = true)
                    MultipartFile file,
            HttpServletRequest request, HttpServletResponse response
    ) {

        // 单体应用中会采用文件流上传，后续会改用oss和fastDFS保存图片
        // 上传图片通常限制在200k以内，需要限制大小。application.xml
        // spring.servlet.multipart.max-file-size: 200KB  # 文件上传大小限制

        // 定义头像保存地址
        String fileSpace = fileUpload.getImageUserFaceLocation();
        // String fileSpace = IMAGE_USER_FACE_LOCATION;
        // 上传路径，用userid标识
        String uploadPath = File.separator + userId;

        // 文件上传操作
        if (file != null) {
            // 获取文件名称
            String fileName = file.getOriginalFilename();
            if (StringUtils.isNoneBlank(fileName)) {
                // 重命名文件
                String[] arr = fileName.split("\\.");
                // 获取后缀名
                String suffix = arr[arr.length - 1];

                // 图片格式限制，以防止后门。黑客会直接攻击web服务器。
                if (!suffix.equalsIgnoreCase("png")
                        && !suffix.equalsIgnoreCase("jpg")
                        && !suffix.equalsIgnoreCase("jpeg")) {
                    return ServerResponse.createByErrorMsg("图片格式不正确！");
                }

                // 重组文件名
                String newFileName = "face-" + userId + "." + suffix;

                // 图像的最终保存位置
                String finalPath = fileSpace + uploadPath + File.separator + newFileName;
                // web访问地址
                uploadPath += ("/" + newFileName);

                File outFile = new File(finalPath);
                if (outFile.getParentFile() != null) {
                    // 创建文件夹
                    outFile.getParentFile().mkdirs();
                }
                // 文件保存到指定目录
                FileOutputStream fos = null;
                InputStream is = null;
                try {
                    fos = new FileOutputStream(outFile);
                    is = file.getInputStream();
                    IOUtils.copy(is, fos);
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (fos != null) {
                            fos.flush();
                            fos.close();
                        }
                        if (is != null) {
                            is.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        } else {
            return ServerResponse.createByErrorMsg("文件不能为空");
        }

        // 由于浏览器可能存在缓存，所以加上时间戳保证更新后的图片可以及时更新
        String finalImageServerUrl =
                fileUpload.getImageServerUrl() + uploadPath + "?t=" + DateUtil.getCurrentDateString(DateUtil.DATE_PATTERN);
        // 更新用户头像到数据库
        Users user = centerUserService.updateFace(userId, finalImageServerUrl);

        // user = setNullProperty(user);
        UsersVO usersVO = convertUsersVO(user);

        // 更新cookie
        CookieUtils.setCookie(request, response, "user", JsonUtils.objectToJson(usersVO), true);


        return ServerResponse.createBySuccess();
    }

    @ApiOperation(value = "修改用户信息", notes = "修改用户信息", httpMethod = "POST")
    @PostMapping("/update")
    public ServerResponse update(
            @ApiParam(name = "userId", value = "用户id", required = true)
            @RequestParam String userId,
            @ApiParam(name = "centerUserBO", value = "用户中心UserBO", required = true)
            @RequestBody @Valid CenterUserBO centerUserBO,
            BindingResult bindingResult,
            HttpServletRequest request, HttpServletResponse response
    ) {

        // 使用hibernate-validator字段校验，校验结果会放到BindingResult中
        // 要想BO中注解生效，需要BO入参加@Valid注解修饰
        if (bindingResult.hasErrors()) {
            Map<String, String> errorMap = getFieldErrors(bindingResult);
            return ServerResponse.createByErrorMap(errorMap);
        }

        Users user = centerUserService.updateUserInfo(userId, centerUserBO);
        // user = setNullProperty(user);
        UsersVO usersVO = convertUsersVO(user);
        // 更新cookie
        CookieUtils.setCookie(request, response, "user", JsonUtils.objectToJson(usersVO), true);

        return ServerResponse.createBySuccess();

    }

    /**
     * BindingResult 字段校验对象的相关处理
     *
     * @param bindingResult
     * @return
     */
    private Map<String, String> getFieldErrors(BindingResult bindingResult) {
        Map<String, String> result = new HashMap<>();
        List<FieldError> errorList = bindingResult.getFieldErrors();
        for (FieldError error : errorList) {
            // 获取校验失败的字段与对应信息
            String errorKey = error.getField();
            String errorMsg = error.getDefaultMessage();
            result.put(errorKey, errorMsg);
        }
        return result;
    }

    private Users setNullProperty(Users result) {
        result.setPassword(null);
        result.setMobile(null);
        result.setEmail(null);
        result.setCreatedTime(null);
        result.setUpdatedTime(null);
        result.setBirthday(null);
        return result;
    }

}
